import axios from 'axios';
import { AppDataSource } from '../config/database';
import { BranchAccount} from '../entity/BranchAccount';
import { User } from '../entity/User'
import {getStrategy} from "../brand/strategyFactory";
import {generateAccessToken, generateRefreshToken} from "./token";
import {Device} from "../entity/Device";

export class AccountManager {
  /**
   * 注册逻辑
   * @param userId
   * @param password
   */
  async register(userId: string, password: string): Promise<void> {
    if (!userId || !userId.trim()) {
      throw new Error('userId cannot be empty');
    }
    if (!password || !password.trim()) {
      throw new Error('password cannot be empty');
    }
    const repo = AppDataSource.getRepository(User);
    const existing = await repo.findOne({where: {userId}});
    if (existing) {
      throw new Error('User already exists');
    }

    const user = new User();
    user.userId = userId;
    user.password = password; // 直接存储原始密码
    await repo.save(user);

    console.log(`[REGISTER] User ${userId} created`);
  }

  /**
   * 登录逻辑：验证用户 + 校验密码
   * @param userId
   * @param password
   */
  async login(userId: string, password: string): Promise<{ token: string; refreshToken: string; sseconid: string }> {
    const repo = AppDataSource.getRepository(User);
    const user = await repo.findOne({where: {userId}});
    if (!user) throw new Error('User not found');

    if (user.password !== password) {
      throw new Error('Password unmatch');
    }

    const token = generateAccessToken({userId});
    const refreshToken = generateRefreshToken({userId});

    // 订阅逻辑
  const deviceRepo = AppDataSource.getRepository(Device);
  const tokenRepo = AppDataSource.getRepository(BranchAccount);
  const devices = await deviceRepo.find({ where: { userId } });
  const tokens = await tokenRepo.find({ where: { userId } });

  const tokenMap = new Map(tokens.map(t => [t.brand, t.token]));

  for (const device of devices) {
    const accessToken = tokenMap.get(device.brand);
    const strategy = getStrategy(device.brand);

    if (accessToken && strategy.subscribeDevice) {
      try {
        await strategy.subscribeDevice(accessToken, device.did);
        console.log(`[SUBSCRIBE] ${device.did} 已订阅`);
      } catch (err: any) {
        console.warn(`[SUBSCRIBE] 订阅 ${device.did} 失败:`, err.message);
      }
    }
  }

  return { token, refreshToken, sseconid:userId };

    //return {token, refreshToken};

  }


  /**
   * 绑定逻辑，用授权码换取 Token 并存储到 BranchAccount 表
   * @param code   授权码
   * @param userId
   * @param brand
   */
  async exchangeCode(
      code: string,
      userId: string,
      brand: string
  ): Promise<void> {
    // 根据品牌创建对应策略实例
    const strategy = getStrategy(brand);

    // 获取到的Token，token有效期（单位h）
    const {access_token, expires_in} = await strategy.exchangeToken(code);

    const expiresAt = new Date(Date.now() + expires_in * 3600 * 1000);

    const repo = AppDataSource.getRepository(BranchAccount);
    const record = await repo.findOne({where: {userId, brand}});

    if (record) {
      // 更新已有记录
      record.token = access_token;
      record.expiresInHour = expires_in;
      record.expiresAt = expiresAt;
      await repo.save(record);
    } else {
      // 插入新记录
      await repo.save({userId, brand, token: access_token, expiresInHour: expires_in, expiresAt});
    }

    console.log(`[Bind] User ${userId} bind with ${brand}`);

  }

  catch(e: any) {
    console.error(`[BIND] Bind failed:`, e.message);
    throw new Error('Account bind failed.');
  }


  /**
   * 解绑逻辑：通知平台 + 删除本地记录
   * @param userId
   * @param brand
   */
  async unbind(userId: string, brand: string): Promise<void> {
  const branchRepo = AppDataSource.getRepository(BranchAccount);
  const deviceRepo = AppDataSource.getRepository(Device);

  const record = await branchRepo.findOne({ where: { userId, brand } });
  if (!record) {
    throw new Error(`No binding found for ${brand}`);
  }

  // 1. 通知第三方平台撤销授权（如有）
  const strategy = getStrategy(brand);
  if ('revokeToken' in strategy && typeof strategy.revokeToken === 'function') {
    try {
      await strategy.revokeToken(record.token);
    } catch (e: any) {
      console.warn(`[UNBIND] 撤销第三方授权失败：${e.message}，继续删除本地数据`);
    }
  }

  // 2. 删除 BranchAccount 和设备信息（原子操作）
  await AppDataSource.transaction(async manager => {
    await manager.delete(BranchAccount, { userId, brand });
    await manager.delete(Device, { userId, brand });
  });

  console.log(`[UNBIND] 用户 ${userId} 成功解绑 ${brand}，并删除对应设备`);
}

  // async unbind(userId: string, brand: string): Promise<void> {
  //   const repo = AppDataSource.getRepository(BranchAccount);
  //   const record = await repo.findOne({where: {userId, brand}});
  //   if (!record) {
  //     throw new Error(`No binding found for ${brand}`);
  //   }
  //
  //   // 通知第三方接口撤销授权
  //   const strategy = getStrategy(brand);
  //   if ('revokeToken' in strategy && typeof strategy.revokeToken === 'function') {
  //     await strategy.revokeToken(record.token);  // 传入 token 进行撤销
  //   }
  //
  //   // 删除数据库记录
  //   await repo.delete({userId, brand});
  //   console.log(`[UNBIND] ${userId} unbind from ${brand}`);
  //}


  /**
   * 查询用户与各品牌账号绑定情况
   * @param userId
   */
  async getBindingStatus(userId: string): Promise<
  { brand: string; isExpired: boolean }[]
> {
  const brands = ['xiaomi', 'midea'];
  const repo = AppDataSource.getRepository(BranchAccount);
  // 添加缓存机制防止重复查询
  const bindings = await repo.find({ where: { userId } });
  const now = new Date();

  // 修复1：使用更高效的查找结构
  const bindingLookup = new Map<string, BranchAccount>();
  bindings.forEach(binding => {
    // 修复2：防止品牌名大小写不一致问题
    const normalizedBrand = binding.brand.toLowerCase();
    bindingLookup.set(normalizedBrand, binding);
  });

  return brands.map(brand => {
    // 统一使用小写比较确保匹配
    const normalizedBrand = brand.toLowerCase();
    const binding = bindingLookup.get(normalizedBrand);

    // 修复3：安全处理可能的空值日期
    if (binding && binding.expiresAt) {
      return {
        brand: brand, // 保持原始品牌名称大小写
        isExpired: binding.expiresAt.getTime() <= now.getTime()
      };
    }
    // 未找到绑定记录或expiresAt为空视为过期
    return {
      brand: brand,
      isExpired: true
    };
  });
}
}
